/*
* File: IFdEventInterface.cpp
* Copyright (c) 2010. Silviu Caragea <silviu@intelliproject.net>
* Created on September 8, 2010, 10:14 PM
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*  1.Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*  2.Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*  3.All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*       This product includes software developed by the University of
*       California, Berkeley and its contributors.
*  4.Neither the name of the University nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "IFdEventInterface-Inl.h"

namespace litevent
{

IFdEventInterface::IFdEventInterface(size_t mxfds) : maxfds(mxfds)
{
#ifndef USE_STL_MAP
    this->fdarray = (fdnode**) calloc(maxfds, sizeof(this->fdarray));
#endif
    
    watchedEvents = 0;
}

IFdEventInterface::~IFdEventInterface()
{

#ifdef USE_STL_MAP
    
    FileDescriptorMap::iterator it = fdMap.begin();

    for(; it!= fdMap.end(); it++)
    {
        fdnode * node = it->second;

        if(node->OnEvent)
            delete node->OnEvent;

        free(node);
    }

#else
    for (size_t i = 0; i < this->maxfds; i++)
        if (this->fdarray[i])
        {
             if(this->fdarray[i]->OnEvent)
                delete this->fdarray[i]->OnEvent;

            free(this->fdarray[i]);
        }

    free(this->fdarray);
#endif
 
}

int IFdEventInterface::fdRegisterEvent(int fd, fd_event_handler handler, void *ctx)
{
    fdnode *node = this->_getNode(fd);

    if(!node)
        return 0;

    node->fd  = fd;
    node->handler = handler;
    node->ctx     = ctx;
    node->events  = 0;

    return 1;
}

void IFdEventInterface::fdUnregisterEvent(int fd)
{

#ifdef USE_STL_MAP

    fdnode *node = NULL;
    FileDescriptorMap::iterator it = this->fdMap.find(fd);

    if(it != fdMap.end())
    {
        node = it->second;

        if(node->OnEvent)
            delete node->OnEvent;
        free(node);

        fdMap.erase(it);
    }
    
#else

    fdnode *node = this->fdarray[fd];

    if(node)
    {
        if(node->OnEvent)
            delete node->OnEvent;

        free(node);
        this->fdarray[fd] = NULL;            
    }
#endif
}

void IFdEventInterface::fdSetEvent(int fd, int events)
{

#ifdef USE_STL_MAP

    FileDescriptorMap::iterator it = this->fdMap.find(fd);

    if(it != fdMap.end())
    {
        fdnode *node = it->second;
        int fde = this->setEvent(node->nodeIndex, fd, events);

        node->events  = events;

        if(node->nodeIndex == -1)
            this->watchedEvents++;

        node->nodeIndex = fde;
    }
    
#else

    int fde = this->setEvent(this->fdarray[fd]->nodeIndex, fd, events);

    this->fdarray[fd]->events = events;

    if(this->fdarray[fd]->nodeIndex == -1)
        this->watchedEvents++;

    this->fdarray[fd]->nodeIndex = fde;
    
#endif
}

int IFdEventInterface::fdDeleteEvent(int fd)
{

#ifdef USE_STL_MAP
    FileDescriptorMap::iterator it = this->fdMap.find(fd);

    if(it != fdMap.end())
    {
        fdnode *node = it->second;
        if(this->deleteEvent(node->nodeIndex,fd) == 1)
            this->watchedEvents--;

        node->events = 0;
        node->nodeIndex = -1;

        return 1;
    }
   
    return 0;
#else

    if (!this->fdarray[fd])
        return 0;
     
    if(this->deleteEvent(this->fdarray[fd]->nodeIndex,fd) == 1)
        this->watchedEvents--;

    this->fdarray[fd]->events = 0;    
    this->fdarray[fd]->nodeIndex = -1;

    return 1;
#endif
}

int IFdEventInterface::makeSocketNonBlock(int fd)
{

#ifdef WIN32
    unsigned long nonblocking = 1;
    ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
#else
    int flags;

    if ((flags = fcntl(fd, F_GETFL, NULL)) < 0)
    {
        util::CLogger::sharedLogger()->WriteFormated("%s.%d: fcntl(%d,F_GETFL) failed ", __FILE__, __LINE__, fd);
	return 0;
    }

    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
    {
	util::CLogger::sharedLogger()->WriteFormated("%s.%d: fcntl(%d,F_SETFL) failed ", __FILE__, __LINE__, fd);
	return 0;
    }
#endif
    return 1;
}

}
